﻿using AdminSystem.Application.Admins.Dto;
using AdminSystem.Domain;
using AdminSystem.Repositories;
using AdminSystem.Util;
using AutoMapper;
using CSRedis;
using IdentityModel;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Security.Claims;
using System.Text;

namespace AdminSystem.Application.Admins
{
    public class AdminService : IAdminService
    {
        private readonly IAdminRepository repository;
        private readonly IConfiguration configuration;
        private readonly IHttpContextAccessor httpContextAccessor;
        private readonly IMemoryCache memoryCache;
        private readonly IDistributedCache distributedCache;
        private readonly CSRedisClient redisClient;
        private readonly IMapper mapper;

        public AdminService(
            IAdminRepository repository,
            IConfiguration configuration,
            IHttpContextAccessor httpContextAccessor,
            IMemoryCache memoryCache,
            IDistributedCache distributedCache,
            CSRedisClient redisClient,
            IMapper mapper)
        {
            this.repository = repository;
            this.configuration = configuration;
            this.httpContextAccessor = httpContextAccessor;
            this.memoryCache = memoryCache;
            this.distributedCache = distributedCache;
            this.redisClient = redisClient;
            this.mapper = mapper;
        }


        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="loginDto"></param>
        /// <returns></returns>
        public async Task<ResultDto<string>> LoginAsync(LoginDto loginDto)
        {
            try
            {
                var admin = await repository.QueryFirstAsync(m => m.UserName == loginDto.UserName);
                if (admin == null)
                {
                    return new ResultDto<string> { StatusCode = StatusCode.Faield, Message = "账号不存在" };
                }
                else
                {
                    if (admin.Password != loginDto.Password.Md5())
                    {
                        return new ResultDto<string> { StatusCode = StatusCode.Faield, Message = "密码错误" };
                    }
                    else
                    {
                        //调用生成Token方法
                        var authInfo = GenerateToken(admin);

                        return new ResultDto<string> { StatusCode = StatusCode.Success, Data = authInfo };

                    }
                }
            }
            catch (Exception e)
            {
                return new ResultDto<string>
                {
                    StatusCode = StatusCode.Faield,
                    Message = e.Message
                };
            }
        }

        public void GetUserInfo()
        {
            var list = httpContextAccessor.HttpContext.User.Claims;
            var name = httpContextAccessor.HttpContext.User.Identity.Name;
            var Identities = httpContextAccessor.HttpContext.User.Identities; ;
        }

        /// <summary>
        /// 生成jwt token
        /// </summary>
        /// <param name="admin"></param>
        /// <returns></returns>
        private string GenerateToken(Admin admin)
        {
            IList<Claim> claims = new List<Claim> {
                                new Claim(JwtClaimTypes.Id, admin.AdminId.ToString()),
                                new Claim(JwtClaimTypes.Name, admin.UserName)
                            };

            //JWT密钥
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"]));

            //算法
            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            //过期时间
            DateTime expires = DateTime.UtcNow.AddMinutes(30);

            //Payload负载
            var token = new JwtSecurityToken(
                issuer: configuration["JwtConfig:Bearer:Issuer"],
                audience: configuration["JwtConfig:Bearer:Audience"],
                claims: claims,
                notBefore: DateTime.UtcNow,
                expires: expires,
                signingCredentials: cred
                );

            var handler = new JwtSecurityTokenHandler();

            //生成令牌
            string jwt = handler.WriteToken(token);

            return jwt;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="createUpdateDto"></param>
        /// <returns></returns>
        public async Task<ResultDto<AdminDto>> CreateAsync(CreateUpdateAdminDto createUpdateDto)
        {
            try
            {
                var entity = mapper.Map<Admin>(createUpdateDto);
                await repository.InsertAsync(entity);

                return new ResultDto<AdminDto>
                {
                    StatusCode = StatusCode.Success,
                    Data = mapper.Map<Admin, AdminDto>(entity)
                };
            }
            catch (Exception ex)
            {
                return new ResultDto<AdminDto>
                {
                    StatusCode = StatusCode.Faield,
                    Message = ex.Message
                };
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<ResultDto<int>> DeleteAsync(int Id)
        {
            return new ResultDto<int>
            {
                Data = await repository.DeleteMany(Id),
                StatusCode = StatusCode.Success
            };
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <returns></returns>
        public async Task<ResultDto<List<AdminDto>>> QueryAsync()
        {
            /*byte[] admins = distributedCache.Get(nameof(Admin));

            if (admins == null)
            {
                var list = await repository.GetAllAsync();
                admins = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(list));
                distributedCache.Set(nameof(Admin), admins, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromSeconds(10) });
            }

            var result = mapper.Map<List<Admin>, List<AdminDto>>(JsonConvert.DeserializeObject<List<Admin>>(Encoding.UTF8.GetString(admins)));

            return new ResultDto<List<AdminDto>>
            {
                Data = result,
                StatusCode = StatusCode.Success
            };*/



            var admins = await redisClient.GetAsync<List<Admin>>(nameof(Admin));
            if (admins == null)
            {
                admins = await repository.GetAllAsync();
                await redisClient.SetAsync(nameof(Admin), admins);

                // 设置缓存
                //await SetAdminRedisAsync<Admin>(admins);
                await admins.SetAdminRedisAsync(redisClient);

            }

            var result = mapper.Map<List<Admin>, List<AdminDto>>(admins);

            await result.SetAdminRedisAsync(redisClient);

            return new ResultDto<List<AdminDto>>
            {
                Data = result,
                StatusCode = StatusCode.Success
            };

            /*List<Admin> admins;
            var admin = memoryCache.TryGetValue<List<Admin>>(nameof(Admin), out admins);

            if (!admin)
            {
                admins = await repository.GetAllAsync();
                memoryCache.Set(nameof(Admin), admins, new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromSeconds(10) });
            }

            var result = mapper.Map<List<Admin>, List<AdminDto>>(admins);

            return new ResultDto<List<AdminDto>>
            {
                Data = result,
                StatusCode = StatusCode.Success
            };*/
        }

        /// <summary>
        /// 设置Admin缓存
        /// </summary>
        /// <param name="admins"></param>
        /// <returns></returns>
        private async Task SetAdminRedisAsync(List<Admin> admins)
        {
            foreach (var item in admins)
            {
                await redisClient.HSetAsync($"Admin:{item.AdminId}", nameof(Admin.AdminId), item.AdminId);
                await redisClient.HSetAsync($"Admin:{item.AdminId}", nameof(Admin.UserName), item.UserName);
                await redisClient.HSetAsync($"Admin:{item.AdminId}", nameof(Admin.Password), item.Password);
                await redisClient.HSetAsync($"Admin:{item.AdminId}", nameof(Admin.Birthday), item.Birthday);
            }
        }

        
    }
}
